﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NUnit.Framework;
using NSsh.Common.Packets;
using NSsh.Common.Types;
using System.IO;
using NUnit.Framework.SyntaxHelpers;
using NSsh.Common.Utility;

namespace NSsh.Common.Tests.Packets
{
    [TestFixture]
    public class KexInitPacketFixture
    {
        [SetUp]
        public void Setup()
        {
            Dependency.Clear();
            Dependency.RegisterTransient<ISecureRandom, SecureRandom>("SecureRandom");
        }

        [Test]
        public void ShouldCreateFromPacketType()
        {
            Packet packet = new KexInitPacket();
            Assert.That(packet.PacketType, Is.EqualTo(PacketType.KexInit), "Incorrect packet type.");
        }

        [Test]
        public void ShouldCreateFromBinaryReader()
        {
            int length = 123;
            int paddingLength = 5;
            byte[] randomPadding = { 0, 1, 2, 3, 4 };
            byte[] cookie = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf };
            byte firstKexPacketFollows = 1;
            string kexAlgorithm = "kex-algorithm";
            string serverHostKeyAlgorithm = "server-hostkey-algorithm";
            string encryptionAlgorithmsClientToServer = "encryption_algorithms_client_to_server";
            string encryptionAlgorithmsServerToClient = "encryption_algorithms_server_to_client";
            string macAlgorithmsClientToServer = "mac_algorithms_client_to_server";
            string macAlgorithmsServerToClient = "mac_algorithms_server_to_client";
            string compressionAlgorithmsClientToServer = "compression_algorithms_client_to_server";
            string compressionAlgorithmsServerToClient = "compression_algorithms_server_to_client";
            string languagesClientToServer = "languages_client_to_server";
            string languagesServerToClient = "languages_server_to_client";
            MemoryStream memoryStream = new MemoryStream();

            BinaryWriter writer = new BinaryWriter(memoryStream);
            writer.WriteBE((uint)length);
            writer.Write((byte)paddingLength);

            writer.Write((byte)PacketType.KexInit);
            writer.Write(cookie);

            writer.Write(new NameList(new List<string> { kexAlgorithm }).ToByteArray());
            writer.Write(new NameList(new List<string> { serverHostKeyAlgorithm }).ToByteArray());
            writer.Write(new NameList(new List<string> { encryptionAlgorithmsClientToServer }).ToByteArray());
            writer.Write(new NameList(new List<string> { encryptionAlgorithmsServerToClient }).ToByteArray());
            writer.Write(new NameList(new List<string> { macAlgorithmsClientToServer }).ToByteArray());
            writer.Write(new NameList(new List<string> { macAlgorithmsServerToClient }).ToByteArray());
            writer.Write(new NameList(new List<string> { compressionAlgorithmsClientToServer }).ToByteArray());
            writer.Write(new NameList(new List<string> { compressionAlgorithmsServerToClient }).ToByteArray());
            writer.Write(new NameList(new List<string> { languagesClientToServer }).ToByteArray());
            writer.Write(new NameList(new List<string> { languagesServerToClient }).ToByteArray());
           
            writer.Write(firstKexPacketFollows);
            writer.Write((uint)0);

            writer.Write(randomPadding);

            // Reset the stream
            memoryStream.Seek(0, SeekOrigin.Begin);

            // Create from the binary reader
            BinaryReader reader = new BinaryReader(memoryStream);
            KexInitPacket kexInitPacket = new KexInitPacket(new SshPacketContext(reader));

            Assert.That(kexInitPacket.KexAlgorithms.Names.Count, Is.EqualTo(1));
            Assert.That(kexInitPacket.ServerHostKeyAlgorithms.Names.Count, Is.EqualTo(1));
            Assert.That(kexInitPacket.EncryptionAlgorithmsClientToServer.Names.Count, Is.EqualTo(1));
            Assert.That(kexInitPacket.EncryptionAlgorithmsServerToClient.Names.Count, Is.EqualTo(1));
            Assert.That(kexInitPacket.MacAlgorithmsClientToServer.Names.Count, Is.EqualTo(1));
            Assert.That(kexInitPacket.MacAlgorithmsServerToClient.Names.Count, Is.EqualTo(1));
            Assert.That(kexInitPacket.CompressionAlgorithmsClientToServer.Names.Count, Is.EqualTo(1));
            Assert.That(kexInitPacket.CompressionAlgorithmsServerToClient.Names.Count, Is.EqualTo(1));
            Assert.That(kexInitPacket.LanguagesClientToServer.Names.Count, Is.EqualTo(1));
            Assert.That(kexInitPacket.LanguagesServerToClient.Names.Count, Is.EqualTo(1));

            Assert.That(kexInitPacket.KexAlgorithms.Names[0], Is.EqualTo(kexAlgorithm));
            Assert.That(kexInitPacket.ServerHostKeyAlgorithms.Names[0], Is.EqualTo(serverHostKeyAlgorithm));
            Assert.That(kexInitPacket.EncryptionAlgorithmsClientToServer.Names[0], Is.EqualTo(encryptionAlgorithmsClientToServer));
            Assert.That(kexInitPacket.EncryptionAlgorithmsServerToClient.Names[0], Is.EqualTo(encryptionAlgorithmsServerToClient));
            Assert.That(kexInitPacket.MacAlgorithmsClientToServer.Names[0], Is.EqualTo(macAlgorithmsClientToServer));
            Assert.That(kexInitPacket.MacAlgorithmsServerToClient.Names[0], Is.EqualTo(macAlgorithmsServerToClient));
            Assert.That(kexInitPacket.CompressionAlgorithmsClientToServer.Names[0], Is.EqualTo(compressionAlgorithmsClientToServer));
            Assert.That(kexInitPacket.CompressionAlgorithmsServerToClient.Names[0], Is.EqualTo(compressionAlgorithmsServerToClient));
            Assert.That(kexInitPacket.LanguagesClientToServer.Names[0], Is.EqualTo(languagesClientToServer));
            Assert.That(kexInitPacket.LanguagesServerToClient.Names[0], Is.EqualTo(languagesServerToClient));

            PacketFixture.ComparePacketByteData(kexInitPacket, memoryStream);
        }
    }
}
